﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.UI;
using Htse.Blue.Models;
using System.Collections;
using Htse.Blue.Models.ViewModels;
using Htse.Blue.Logic;

namespace Htse.Blue.Controllers
{

	[HandleError]
	public class AccountController : Controller
	{

		// This constructor is used by the MVC framework to instantiate the controller using
		// the default forms authentication and membership providers.

		public AccountController()
			: this(null, null)
		{
			//var roles = MembershipService.GetAllRoles();
			//MembershipService.CreateUser("Yuri", "yuri10", "yuri.macchiavelli@gmail.com");
			//MembershipService.AddUserToRole("Yuri", SiteConstants.USER_ACCOUNT);
			//MembershipService.AddUserToRole("Yuri", SiteConstants.ADMIN_ACCOUNT);
		}

		// This constructor is not used by the MVC framework but is instead provided for ease
		// of unit testing this type. See the comments at the end of this file for more
		// information.
		public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
		{
			FormsAuth = formsAuth ?? new FormsAuthenticationService();
			MembershipService = service ?? new AccountMembershipService();
		}

		public IFormsAuthentication FormsAuth
		{
			get;
			private set;
		}

		public IMembershipService MembershipService
		{
			get;
			private set;
		}

		public ActionResult LogOn()
		{

			return View();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
			 Justification = "Needs to take same parameter type as Controller.Redirect()")]
		public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
		{

			if (!ValidateLogOn(userName, password))
			{
				return View();
			}

			FormsAuth.SignIn(userName, rememberMe);
			if (!String.IsNullOrEmpty(returnUrl))
			{
				return Redirect(returnUrl);
			}
			else
			{
				return RedirectToAction("Index", "Home");
			}
		}

		public ActionResult LogOff()
		{

			FormsAuth.SignOut();

			return RedirectToAction("Index", "Home");
		}

		public ActionResult Register()
		{
			ViewData["PasswordLength"] = MembershipService.MinPasswordLength;

			return View();
		}

		[Authorize(Roles = SiteConstants.ADMIN_ACCOUNT)]
		[AcceptVerbs(HttpVerbs.Post)]
		public ActionResult Register(string userName, string email, string password, string confirmPassword)
		{
			ViewData["PasswordLength"] = MembershipService.MinPasswordLength;

			if (ValidateRegistration(userName, email, password, confirmPassword))
			{
				// Attempt to register the user
				MembershipCreateStatus createStatus = MembershipService.CreateUser(userName, password, email);

				if (createStatus == MembershipCreateStatus.Success)
				{
					return RedirectToAction("AddUserRoleToUser", "Account", new { userName = userName });
				}
				else
				{
					ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus));
				}
			}

			// If we got this far, something failed, redisplay form
			return View();
		}

		[Authorize(Roles=SiteConstants.ADMIN_ACCOUNT)]
		[AcceptVerbs(HttpVerbs.Get)]
		public ActionResult AddUserRoleToUser(string userName)
		{
			var roles = MembershipService.GetAllRoles();

			MembershipService.AddUserToRole(userName, SiteConstants.USER_ACCOUNT);

			return RedirectToAction("List", "Account");
		}

		[Authorize]
		public ActionResult ChangePassword()
		{
			ViewData["PasswordLength"] = MembershipService.MinPasswordLength;

			return View();
		}

		[Authorize]
		[AcceptVerbs(HttpVerbs.Post)]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
			 Justification = "Exceptions result in password not being changed.")]
		public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword)
		{
			ViewData["PasswordLength"] = MembershipService.MinPasswordLength;

			if (!ValidateChangePassword(currentPassword, newPassword, confirmPassword))
			{
				return View();
			}

			try
			{
				if (MembershipService.ChangePassword(User.Identity.Name, currentPassword, newPassword))
				{
					return RedirectToAction("ChangePasswordSuccess");
				}
				else
				{
					ModelState.AddModelError("_FORM", "La password corrente non è valida o la nuova password non è corretta.");
					return View();
				}
			}
			catch
			{
				ModelState.AddModelError("_FORM", "La password corrente non è valida o la nuova password non è corretta.");
				return View();
			}
		}

		public ActionResult ChangePasswordSuccess()
		{
			return View();
		}

		[Authorize(Roles = SiteConstants.ADMIN_ACCOUNT)]
		public ActionResult List(int? page, string sort)
		{
			var users = MembershipService.ListUsers(page ,SiteConstants.PAGE_SIZE, sort);

			if (Request.IsAjaxRequest())
			{
				return PartialView("AccountList", new AccountListViewModel(users));
			}
			else
			{
				return View("List", new AccountListViewModel(users));
			}
		}

		[Authorize(Roles = SiteConstants.ADMIN_ACCOUNT)]
		[AcceptVerbs(HttpVerbs.Delete)]
		[ActionName("Delete")]
		public ActionResult AjaxDelete(string id)
		{
			MembershipService.DeleteUser(id);

			return RedirectToAction("List");
		}

		protected override void OnActionExecuting(ActionExecutingContext filterContext)
		{
			if (filterContext.HttpContext.User.Identity is WindowsIdentity)
			{
				throw new InvalidOperationException("Windows authentication is not supported.");
			}
		}

		#region Validation Methods

		private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword)
		{
			if (String.IsNullOrEmpty(currentPassword))
			{
				ModelState.AddModelError("currentPassword", "Devi inserire la password attuale.");
			}
			if (newPassword == null || newPassword.Length < MembershipService.MinPasswordLength)
			{
				ModelState.AddModelError("newPassword",
					 String.Format(CultureInfo.CurrentCulture,
							"Devi specificare una password di {0} più caratteri.",
							MembershipService.MinPasswordLength));
			}

			if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal))
			{
				ModelState.AddModelError("_FORM", "La nuova password e la password di conferma sono diverse.");
			}

			return ModelState.IsValid;
		}

		private bool ValidateLogOn(string userName, string password)
		{
			if (String.IsNullOrEmpty(userName))
			{
				ModelState.AddModelError("username", "Devi specificare un nome utente.");
			}
			if (String.IsNullOrEmpty(password))
			{
				ModelState.AddModelError("password", "Devi specificare una password.");
			}
			if (!MembershipService.ValidateUser(userName, password))
			{
				ModelState.AddModelError("_FORM", "L'utente o la password immessi non sono corretti.");
			}

			return ModelState.IsValid;
		}

		private bool ValidateRegistration(string userName, string email, string password, string confirmPassword)
		{
			if (String.IsNullOrEmpty(userName))
			{
				ModelState.AddModelError("username", "You must specify a username.");
			}
			if (String.IsNullOrEmpty(email))
			{
				ModelState.AddModelError("email", "You must specify an email address.");
			}
			if (password == null || password.Length < MembershipService.MinPasswordLength)
			{
				ModelState.AddModelError("password",
					 String.Format(CultureInfo.CurrentCulture,
							"You must specify a password of {0} or more characters.",
							MembershipService.MinPasswordLength));
			}
			if (!String.Equals(password, confirmPassword, StringComparison.Ordinal))
			{
				ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
			}
			return ModelState.IsValid;
		}

		private static string ErrorCodeToString(MembershipCreateStatus createStatus)
		{
			// See http://msdn.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx for
			// a full list of status codes.
			switch (createStatus)
			{
				case MembershipCreateStatus.DuplicateUserName:
					return "Username already exists. Please enter a different user name.";

				case MembershipCreateStatus.DuplicateEmail:
					return "A username for that e-mail address already exists. Please enter a different e-mail address.";

				case MembershipCreateStatus.InvalidPassword:
					return "The password provided is invalid. Please enter a valid password value.";

				case MembershipCreateStatus.InvalidEmail:
					return "The e-mail address provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidAnswer:
					return "The password retrieval answer provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidQuestion:
					return "The password retrieval question provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidUserName:
					return "The user name provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.ProviderError:
					return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

				case MembershipCreateStatus.UserRejected:
					return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

				default:
					return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
			}
		}
		#endregion
	}
}
